package com.zishuimuyu.trans.factory;

import com.zishuimuyu.trans.AbstractOnlineTranslator;
import com.zishuimuyu.trans.Translator;
import com.zishuimuyu.trans.annotation.TranslatorComponent;
import com.zishuimuyu.trans.exception.DupIdException;
import com.zishuimuyu.trans.impl.BaiduTranslator;
import com.zishuimuyu.trans.impl.GoogleTranslator;
import com.zishuimuyu.trans.impl.JinshanTranslator;
import com.zishuimuyu.trans.impl.OmiTranslator;
import com.zishuimuyu.trans.impl.TencentTranslator;
import com.zishuimuyu.trans.impl.YoudaoTranslator;

import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 抽象翻译器工厂类，实现了 TFactory 接口。
 * 该工厂类用于初始化系统翻译器和用户自定义翻译器，并将它们存储在一个映射中。
 */
public abstract class AbstractTranslatorFactory implements TFactory {
    /**
     * 存储翻译器的映射，键为翻译器的 ID，值为对应的翻译器实例。
     */
    protected Map<String, Translator> translatorMap = new HashMap<>();
    /**
     * 存储工作包名的列表，用于查找用户自定义的翻译器类。
     */
    private List<String> workPackages = new ArrayList<>();

    /**
     * 存储系统内置翻译器类的列表。
     */
    private List<Class<? extends AbstractOnlineTranslator>> translatorClasses = Arrays.asList(
            // 百度翻译器类
            BaiduTranslator.class,
            // 谷歌翻译器类
            GoogleTranslator.class,
            // 金山翻译器类
            JinshanTranslator.class,
            // 腾讯翻译器类
            TencentTranslator.class,
            // Omi 翻译器类
            OmiTranslator.class,
            // 有道翻译器类
            YoudaoTranslator.class);

    /**
     * 无参构造函数，初始化系统翻译器和用户自定义翻译器。
     *
     * @throws ClassNotFoundException 如果找不到指定的类
     * @throws InstantiationException 如果实例化类时发生错误
     * @throws IllegalAccessException 如果访问类的构造函数或方法时发生非法访问
     * @throws DupIdException         如果翻译器 ID 重复
     * @throws URISyntaxException     如果 URI 语法错误
     */
    public AbstractTranslatorFactory() throws ClassNotFoundException, InstantiationException, IllegalAccessException, DupIdException, URISyntaxException {
        // 初始化系统翻译器
        initSystemTranslator();
        // 初始化用户自定义翻译器
        initUserTranslator();
    }

    /**
     * 带工作包名数组的构造函数，调用无参构造函数并初始化用户自定义翻译器。
     *
     * @param workPackages 工作包名数组
     * @throws ClassNotFoundException 如果找不到指定的类
     * @throws InstantiationException 如果实例化类时发生错误
     * @throws IllegalAccessException 如果访问类的构造函数或方法时发生非法访问
     * @throws DupIdException         如果翻译器 ID 重复
     * @throws URISyntaxException     如果 URI 语法错误
     */
    public AbstractTranslatorFactory(String[] workPackages) throws ClassNotFoundException, InstantiationException, IllegalAccessException, DupIdException, URISyntaxException {
        // 调用无参构造函数
        this();
    }

    /**
     * 带单个工作包名的构造函数，将单个工作包名转换为数组并调用带数组的构造函数。
     *
     * @param workPackage 单个工作包名
     * @throws ClassNotFoundException 如果找不到指定的类
     * @throws InstantiationException 如果实例化类时发生错误
     * @throws IllegalAccessException 如果访问类的构造函数或方法时发生非法访问
     * @throws DupIdException         如果翻译器 ID 重复
     * @throws URISyntaxException     如果 URI 语法错误
     */
    public AbstractTranslatorFactory(String workPackage) throws ClassNotFoundException, InstantiationException, IllegalAccessException, DupIdException, URISyntaxException {
        // 调用带工作包名数组的构造函数
        this(new String[]{workPackage});
    }

    /**
     * 初始化系统内置的翻译器。
     *
     * @throws ClassNotFoundException 如果找不到指定的类
     * @throws InstantiationException 如果实例化类时发生错误
     * @throws IllegalAccessException 如果访问类的构造函数或方法时发生非法访问
     * @throws DupIdException         如果翻译器 ID 重复
     * @throws URISyntaxException     如果 URI 语法错误
     */
    private void initSystemTranslator() throws ClassNotFoundException, InstantiationException, IllegalAccessException, DupIdException, URISyntaxException {
        // 遍历系统内置翻译器类列表
        for (Class<?> translatorClass : translatorClasses) {
            // 获取翻译器类上的 TranslatorComponent 注解
            TranslatorComponent component = translatorClass.getAnnotation(TranslatorComponent.class);
            if (component != null) {
                // 获取翻译器的 ID
                String id = component.id();
                if (translatorMap.containsKey(id)) {
                    // 如果 ID 已存在，抛出 ID 重复异常
                    throw new DupIdException("Id duplication exception");
                } else {
                    // 将翻译器实例添加到映射中
                    translatorMap.put(component.id(), (Translator) translatorClass.newInstance());
                }
            }
        }
    }

    /**
     * 初始化用户自定义的翻译器。
     *
     * @throws ClassNotFoundException 如果找不到指定的类
     * @throws InstantiationException 如果实例化类时发生错误
     * @throws IllegalAccessException 如果访问类的构造函数或方法时发生非法访问
     * @throws DupIdException         如果翻译器 ID 重复
     * @throws URISyntaxException     如果 URI 语法错误
     */
    private void initUserTranslator() throws ClassNotFoundException, InstantiationException, IllegalAccessException, DupIdException, URISyntaxException {
        // 遍历工作包名列表
        for (String workPackage : workPackages) {
            // 获取指定包下的所有类名
            List<String> workClassesName = getClassNameByPackage(workPackage);
            // 遍历类名列表
            for (String workClassName : workClassesName) {
                // 加载类
                Class<?> workClass = Class.forName(workClassName);
                // 获取类上的 TranslatorComponent 注解
                TranslatorComponent component = workClass.getAnnotation(TranslatorComponent.class);
                if (component != null) {
                    // 获取翻译器的 ID
                    String id = component.id();
                    if (translatorMap.containsKey(id)) {
                        // 如果 ID 已存在，抛出 ID 重复异常
                        throw new DupIdException("Id duplication exception");
                    } else {
                        // 将翻译器实例添加到映射中
                        translatorMap.put(component.id(), (Translator) workClass.newInstance());
                    }
                }
            }
        }
    }

    /**
     * 根据包名获取该包下的所有类名。
     *
     * @param packageName 包名
     * @return 类名列表
     * @throws URISyntaxException 如果 URI 语法错误
     */
    private List<String> getClassNameByPackage(String packageName) throws URISyntaxException {
        // 存储类名的列表
        List<String> classesName = new ArrayList<>();
        // 获取类加载器
        ClassLoader loader = getClass().getClassLoader();
        // 获取包对应的资源 URL
        URL url = loader.getResource(packageName.replace(".", "/"));

        // 根据 URL 创建文件对象
        File packageDir = new File(new URI(url.getPath()).getPath());
        // 遍历包目录下的所有文件
        for (File classFile : packageDir.listFiles()) {
            // 获取文件名
            String classNickName = classFile.getName();
            // 去除文件扩展名
            classNickName = classNickName.substring(0, classNickName.indexOf('.'));
            // 将完整类名添加到列表中
            classesName.add(packageName + "." + classNickName);
        }
        return classesName;
    }
}

